#include "StdAfx.h"
#include "HXTTSEngineSAPI.h"

string HXTTSEngineSAPI::aMapVisemeToImage[22] = { "",  // SP_VISEME_0 = 0,    // Silence
                                                "{", // SP_VISEME_1,        // AE, AX, AH
                                                "A", // SP_VISEME_2,        // AA
                                                "O", // SP_VISEME_3,        // AO
                                                "EI", // SP_VISEME_4,        // EY, EH, UH
                                                "r=", // SP_VISEME_5,        // ER
                                                "j",  // SP_VISEME_6,        // y, IY, IH, IX
                                                "w",  // SP_VISEME_7,        // w, UW
                                                "@U", // SP_VISEME_8,        // OW
                                                "aU",  // SP_VISEME_9,        // AW
                                                "OI", // SP_VISEME_10,       // OY
                                                "AI", // SP_VISEME_11,       // AY
                                                "h",  // SP_VISEME_12,       // h
                                                "r",  // SP_VISEME_13,       // r
                                                "n",  // SP_VISEME_14,       // l
                                                "s",  // SP_VISEME_15,       // s, z
                                                "tS",  // SP_VISEME_16,       // SH, CH, JH, ZH
                                                "T",  // SP_VISEME_17,       // TH, DH
                                                "f",  // SP_VISEME_18,       // f, v
                                                "d",  // SP_VISEME_19,       // d, t, n
                                                "g",  // SP_VISEME_20,       // k, g, NG
                                                "p" };// SP_VISEME_21,       // p, b, m

// these were compiled from http://msdn.microsoft.com/en-us/library/ms720566(v=vs.85).aspx
// they are the new basic shapes to send to visemes.hxml
string HXTTSEngineSAPI::aMapChinesePhonemeToImage[424] = {
												"", // Nothing
												"-", //"-", 1 Syllable  boundary    (hyphen)
												"!", //"!", 2 Sentence terminator    (exclamation mark)
												"&", //"&", 3 word boundary    
												",", //",", 4 Sentence terminator    (comma)
												".", //".", 5 Sentence terminator    (period)
												"?", //"?", 6 Sentence terminator    (question mark)
												"_", //"_", 7 Silence    (underscore)
												"+", //"+", 8 primary stress    
												"*", //"*", 9 secondary stress    
												"1", //"1", 10 Tone 1   
												"2", //"2", 11 Tone 2   
												"3", //"3", 12 Tone 3   
												"4", //"4", 13 Tone 4   
												"5", //"5", 14 Tone 5   
												"a", //"a", 15 a 1 fei 1 (rogue)
												"ai", //"ai", 16 ai 4 ren 2 (lover)
												"an", //"an", 17 an 1 quan 2 (safe)
												"ang", //"ang", 18 ang 1 zang 1 (dirty)
												"ao", //"ao", 19 jiao 1 ao 4 (proud)
												"ba", //"ba", 20 ba 4 ba 5 (dad)
												"bai", //"bai", 21 bai 2 se 4 (white)
												"ban", //"ban", 22 mu 4 ban 3 (board)
												"bang", //"bang", 23 bang 3 jia 4 (kidnap)
												"bao", //"bao", 24 yong 1 bao 4 (embrace)
												"bei", //"bei", 25 bei 3 fang 1 (north)
												"ben", //"ben", 26 ben 4 dan 4 (fool)
												"beng", //"beng", 27 beng 4 tiao 4 (jump)
												"bi", //"bi", 28 bi 2 zi 5 (nose)
												"bian", //"bian", 29 bian 4 hua 5 (change)
												"biao", //"biao", 30 biao 3 ge 2 (table)
												"bie", //"bie", 31 li 2 bie 2 (part with)
												"bin", //"bin", 32 bin 1 ke 4 (guest)
												"bing", //"bing", 33 shi 4 bing 1 (soldier)
												"bo", //"bo", 34 bo 2 dou 4 (wrestle)
												"bu", //"bu", 35 bu 4 xing 2 (walk)
												"ca", //"ca", 36 ca 1 gan 1 (wipe)
												"cai", //"cai", 37 cai 1 ce 4 (guess)
												"can", //"can", 38 can 1 jia 1 (join)
												"cang", //"cang", 39 cang 1 ying 5 (fly)
												"cao", //"cao", 40 cao 1 chang 3 (playground)
												"ce", //"ce", 41 ce 4 liang 2 (measure)
												"cen", //"cen", 42 cen 1 ci 1 (uneven)
												"ceng", //"ceng", 43 ceng 2 jing 1 (once)
												"cha", //"cha", 44 jian 3 cha 2 (check)
												"chai", //"chai", 45 chai 1 hui 3 (demolish)
												"chan", //"chan", 46 chan 3 ye 4 (industry)
												"chang", //"chang", 47 jing 1 chang 2 (often)
												"chao", //"chao", 48 chao 1 yue 4 (exceed)
												"che", //"che", 49 qi 4 che 1 (automobile)
												"chen", //"chen", 50 chen 2 jiu 4 (old)
												"cheng", //"cheng", 51 cheng 2 che 1 (ride)
												"chi", //"chi", 52 chi 2 dao 4 (late for)
												"chong", //"chong", 53 chong 1 man 3 (full of)
												"chou", //"chou", 54 chou 2 hen 4 (hatred)
												"chu", //"chu", 55 chu 2 fa 3 (division)
												"chuai", //"chuai", 56 chuai 3 ce 4 (guess)
												"chuan", //"chuan", 57 lun 2 chuan 2 (ship)
												"chuang", //"chuang", 58 chuang 4 ye 4 (carve out)
												"chui", //"chui", 59 tie 3 chui 2 (hammer)
												"chun", //"chun", 60 chun 1 tian 1 (spring)
												"chuo", //"chuo", 61 wo 4 chuo 4 (dirty)
												"ci", //"ci", 62 ci 2 qi 4 (porcelain)
												"cong", //"cong", 63 cong 2 lin 2 (thicket)
												"cou", //"cou", 64 jin 3 cou 4 (compact)
												"cu", //"cu", 65 cu 4 xiao 1 (sales promotion)
												"cuan", //"cuan", 66 tao 2 cuan 4 (run away)
												"cui", //"cui", 67 cui 1 cu 4 (press)
												"cun", //"cun", 68 xiang 1 cun 1 (country)
												"cuo", //"cuo", 69 cuo 4 wu 4 (error)
												"da", //"da", 70 da 4 (big)  
												"dai", //"dai", 71 dai 4 biao 3 (delegate)
												"dan", //"dan", 72 dan 4 shi 4 (but)
												"dang", //"dang", 73 dang 1 ran 2 (sure)
												"dao", //"dao", 74 dao 1   (knife)
												"de", //"de", 75 de 5   (function word)
												"dei", //"dei", 76 dei 3   (must)
												"den", //"den", 77 den 4   (yank)
												"deng", //"deng", 78 ban 3 deng 4 (wooden stool)
												"di", //"di", 79 di 2 que 4 (certainly)
												"dia", //"dia", 80 dia 3   (coquetry voice)
												"dian", //"dian", 81 dian 3   (dot)
												"diao", //"diao", 82 diao 4   (hang)
												"die", //"die", 83 die 1 dao 3 (tumble)
												"ding", //"ding", 84 jue 2 ding 4 (decide)
												"diu", //"diu", 85 diu 1 qi 4 (discard)
												"dong", //"dong", 86 dong 1 fang 1 (east)
												"dou", //"dou", 87 zhan 4 dou 4 (struggle)
												"du", //"du", 88 du 4 jue 2 (stop)
												"duan", //"duan", 89 duan 3   (short)
												"dui", //"dui", 90 dui 4   (right)
												"dun", //"dun", 91 ting 2 dun 4 (halt)
												"duo", //"duo", 92 duo 1 yu 2 (unnecessary)
												"e", //"e", 93 e 4   (hungry)
												"ei", //"ei", 94 ei 4   (yes)
												"en", //"en", 95 en 1 hui 4 (favor)
												"er", //"er", 96 er 3   (ear)
												"fa", //"fa", 97 fa 1 zhan 3 (development)
												"fan", //"fan", 98 fan 4   (rice)
												"fang", //"fang", 99 fang 2 jian 1 (room)
												"fei", //"fei", 100 fei 1   (fly)
												"fen", //"fen", 101 fen 1 bie 2 (separate)
												"feng", //"feng", 102 feng 1   (wind)
												"fo", //"fo", 103 fo 2   (buddha)
												"fou", //"fou", 104 fou 3 ding 4 (denial)
												"fu", //"fu", 105 fu 4 qin 1 (father)
												"ga", //"ga", 106 gan 1 ga 4 (awkward)
												"gai", //"gai", 107 ying 1 gai 1 (should)
												"gan", //"gan", 108 gan 1 jing 4 (neatness)
												"gang", //"gang", 109 gang 1 cai 2 (just)
												"gao", //"gao", 110 gao 1   (tall)
												"ge", //"ge", 111 pin 3 ge 2 (character)
												"gei", //"gei", 112 gei 3 yu 3 (give)
												"gen", //"gen", 113 gen 1   (root)
												"geng", //"geng", 114 geng 4 jia 1 (much more)
												"gong", //"gong", 115 gong 1 ren 2 (worker)
												"gou", //"gou", 116 zu 2 gou 4 (enough)
												"gu", //"gu", 117 gu 4 xiang 1 (hometown)
												"gua", //"gua", 118 xi 1 gua 1 (watermelon)
												"guai", //"guai", 119 qi 2 guai 4 (oddness)
												"guan", //"guan", 120 guan 1 bi 4 (close)
												"guang", //"guang", 121 guang 1   (light)
												"gui", //"gui", 122 gui 3   (ghost)
												"gun", //"gun", 123 gun 4   (stick)
												"guo", //"guo", 124 guo 4 qu 4 (past)
												"ha", //"ha", 125 ha 1 (sound of laugh)
												"hai", //"hai", 126 hai 2 zi 5 (child)
												"han", //"han", 127 chu 1 han 4 (sweat)
												"hang", //"hang", 128 hang 2 xing 2 (sail)
												"hao", //"hao", 129 hao 3   (good)
												"he", //"he", 130 he 2   (river)
												"hei", //"hei", 131 hei 1   (black)
												"hen", //"hen", 132 hen 3   (very)
												"heng", //"heng", 133 heng 2 xiang 4 (landscape orientation)
												"hong", //"hong", 134 hong 2   (red)
												"hou", //"hou", 135 hou 2 zi 5 (monkey)
												"hu", //"hu", 136 hu 2 xu 1 (beard)
												"hua", //"hua", 137 hua 4   (picture)
												"huai", //"huai", 138 huai 4   (bad)
												"huan", //"huan", 139 huan 2 jing 4 (environment)
												"huang", //"huang", 140 huang 2 se 4 (yellow)
												"hui", //"hui", 141 hui 1 huang 2 (refulgence)
												"hun", //"hun", 142 hun 2 zhuo 2 (muddy)
												"huo", //"huo", 143 huo 3   (fire)
												"ji", //"ji", 144 ji 2 shi 2 (in time)
												"jia", //"jia", 145 jia 4 qi 1 (holiday)
												"jian", //"jian", 146 jian 3 dan 1 (simple)
												"jiang", //"jiang", 147 jiang 1   (river)
												"jiao", //"jiao", 148 jiao 1 tong 1 (traffic)
												"jie", //"jie", 149 jie 2 ri 4 (feast)
												"jin", //"jin", 150 jin 3 zhang 1 (strain)
												"jing", //"jing", 151 gan 1 jing 4 (neatness)
												"jiong", //"jiong", 152 jiong 3 po 4 (embarrassed)
												"jiu", //"jiu", 153 jiu 3   (nine)
												"ju", //"ju", 154 ju 4 zi 5 (sentence)
												"juan", //"juan", 155 juan 3 qu 1 (curl)
												"jue", //"jue", 156 jue 2 ding 4 (decide)
												"jun", //"jun", 157 jun 1 dui 4 (army)
												"ka", //"ka", 158 ka 3 che 1 (truck)
												"kai", //"kai", 159 kai 3 xuan 2 (triumph)
												"kan", //"kan", 160 kan 4   (see)
												"kang", //"kang", 161 di 3 kang 4 (resist)
												"kao", //"kao", 162 kao 3 shi 4 (test)
												"ke", //"ke", 163 ke 3   (thirsty)
												"kei", //"kei", 164 kei 1   (scold)
												"ken", //"ken", 165 ken 3 ding 4 (affirm)
												"keng", //"keng", 166 keng 1 hai 4 (entrap)
												"kong", //"kong", 167 kong 1 qi 4 (air)
												"kou", //"kou", 168 kou 3   (mouth)
												"ku", //"ku", 169 jian 1 ku 3 (trial)
												"kua", //"kua", 170 kua 1 jiang 3 (praise)
												"kuai", //"kuai", 171 kuai 4   (fast)
												"kuan", //"kuan", 172 kuan 1 kuo 4 (openness)
												"kuang", //"kuang", 173 kong 1 kuang 4 (void)
												"kui", //"kui", 174 kui 1 qian 4 (owe)
												"kun", //"kun", 175 kun 4 nan 2 (hard)
												"kuo", //"kuo", 176 kuo 4 da 4 (enlarge)
												"la", //"la", 177 la 4 jiao 1 (hot pepper)
												"lai", //"lai", 178 lai 2   (come)
												"lan", //"lan", 179 lan 2 se 4 (blue)
												"lang", //"lang", 180 lang 2   (wolf)
												"lao", //"lao", 181 lao 3   (old)
												"le", //"le", 182 kuai 4 le 4 (happy)
												"lei", //"lei", 183 lei 2   (thunder)
												"leng", //"leng", 184 leng 3 ku 4 (steeliness)
												"li", //"li", 185 li 2   (pear)
												"lia", //"lia", 186 lia 2   (two)
												"lian", //"lian", 187 lian 3   (face)
												"liang", //"liang", 188 li 4 liang 4 (power)
												"liao", //"liao", 189 zuo 2 liao 4 (seasoning)
												"lie", //"lie", 190 lin 3 lie 4 (severe)
												"lin", //"lin", 191 lin 3 lie 4 (severe)
												"ling", //"ling", 192 ling 2 mu 4 (mausoleum)
												"liu", //"liu", 193 liu 2 dong 4 (flow)
												"lo", //"lo", 194 lo 5   (function word)
												"long", //"long", 195 long 2   (dragon)
												"lou", //"lou", 196 lou 4   (leak)
												"lu", //"lu", 197 lu 4 di 4 (land)
												"luan", //"luan", 198 hun 4 luan 4 (chaos)
												"lue", //"lue", 199 ce 4 lue 4 (tactic)
												"lun", //"lun", 200 yi 4 lun 4 (discuss)
												"luo", //"luo", 201 xia 4 luo 4 (whereabouts)
												"lv", //"lv", 202 lv 4 se 4 (green)
												"ma", //"ma", 203 ma 3   (horse)
												"mai", //"mai", 204 mai 2 zang 4 (bury)
												"man", //"man", 205 man 3 zu 2 (satisfy)
												"mang", //"mang", 206 cong 1 mang 2 (hurry)
												"mao", //"mao", 207 mao 1   (cat)
												"me", //"me", 208 shen 2 me 5 (what)
												"mei", //"mei", 209 mei 2 you 3 (no)
												"men", //"men", 210 wo 3 men 2 (we)
												"meng", //"meng", 211 meng 4   (dream)
												"mi", //"mi", 212 hun 1 mi 2 (coma)
												"mian", //"mian", 213 mian 4 ji 5 (area)
												"miao", //"miao", 214 miao 4   (temple)
												"mie", //"mie", 215 mie 4 jue 2 (annihilation)
												"min", //"min", 216 ren 2 min 2 (people)
												"ming", //"ming", 217 ming 2 bai 2 (clearness)
												"miu", //"miu", 218 huang 1 miu 4 (absurd)
												"mo", //"mo", 219 mo 4 shui 3 (ink)
												"mou", //"mou", 220 mou 2 lue 4 (trick)
												"mu", //"mu", 221 mu 4 biao 1 (target)
												"na", //"na", 222 na 4 li 3 (there)
												"nai", //"nai", 223 nai 3 nai 5 (grandmother)
												"nan", //"nan", 224 nan 2 fang 1 (south)
												"nang", //"nang", 225 nang 2 kuo 4 (include)
												"nao", //"nao", 226 re 4 nao 4 (liveliness)
												"ne", //"ne", 227 mu 4 ne 4 (numb)
												"nei", //"nei", 228 nei 4 bu 4 (inside)
												"nen", //"nen", 229 nen 4 lv 4 (light green)
												"neng", //"neng", 230 neng 2 gou 4 (be  capable of)
												"ni", //"ni", 231 ni 3   (you)
												"nian", //"nian", 232 nian 2   (year)
												"niang", //"niang", 233 gu 1 niang 5 (girl)
												"niao", //"niao", 234 niao 3   (bird)
												"nie", //"nie", 235 nie 4   (bite)
												"nin", //"nin", 236 nin 2   (you)
												"ning", //"ning", 237 an 1 ning 2 (peace)
												"niu", //"niu", 238 niu 2   (bull)
												"nong", //"nong", 239 nong 2 min 2 (farmer)
												"nou", //"nou", 240 nou 4   (weeding)
												"nu", //"nu", 241 nu 3 li 4 (try hard)
												"nuan", //"nuan", 242 wen 1 nuan 3 (warm)
												"nue", //"nue", 243 nue 4 dai 4 (abuse)
												"nuo", //"nuo", 244 nuo 4 yan 2 (promise)
												"nv", //"nv", 245 nv 3 zi 3 (woman)
												"o", //"o", 246 o 5   (function word)
												"ou", //"ou", 247 ou 1 yang 2 (Chinese first name)
												"pa", //"pa", 248 hai 4 pa 4 (scare)
												"pai", //"pai", 249 pai 4 qian 3 (send)
												"pan", //"pan", 250 pan 4 tu 2 (betrayer)
												"pang", //"pang", 251 pang 2 da 4 (huge)
												"pao", //"pao", 252 pao 3   (run)
												"pei", //"pei", 253 pei 2 ban 4 (accompany)
												"pen", //"pen", 254 pen 2 di 4 (pan)
												"peng", //"peng", 255 peng 2 pai 4 (surge)
												"pi", //"pi", 256 pi 2 fu 1 (skin)
												"pian", //"pian", 257 qi 1 pian 4 (cheat)
												"piao", //"piao", 258 piao 4 liang 4 (pretty)
												"pie", //"pie", 259 pie 1 kai 1 (put aside)
												"pin", //"pin", 260 pin 2 fan 2 (frequency)
												"ping", //"ping", 261 ping 2 zi 5 (bottle)
												"po", //"po", 262 po 4 huai 4 (damage)
												"pou", //"pou", 263 pou 2   (hold something with cupped hand)
												"pu", //"pu", 264 pu 2 tao 5 (grape)
												"qi", //"qi", 265 qi 3 qiu 2 (beg)
												"qia", //"qia", 266 qia 4 dang 4 (proper)
												"qian", //"qian", 267 qian 1 xu 1 (humility)
												"qiang", //"qiang", 268 qiang 2 da 4 (powerful)
												"qiao", //"qiao", 269 qiao 3 miao 4 (artifice)
												"qie", //"qie", 270 xiu 1 qie 4 (shyness)
												"qin", //"qin", 271 qin 1 zi 4 (oneself)
												"qing", //"qing", 272 qing 1 song 1 (easy)
												"qiong", //"qiong", 273 qiong 2   (poverty)
												"qiu", //"qiu", 274 qiu 2 fan 4 (prisoner)
												"qu", //"qu", 275 qu 1 dong 4 (drive)
												"quan", //"quan", 276 quan 2 bu 4 (all)
												"que", //"que", 277 que 4 ding 4 (ensure)
												"qun", //"qun", 278 qun 2 zhong 4 (crowd)
												"ran", //"ran", 279 ran 2 hou 4 (then)
												"rang", //"rang", 280 tu 3 rang 3 (soil)
												"rao", //"rao", 281 wei 2 rao 4 (surround)
												"re", //"re", 282 re 4   (hot)
												"ren", //"ren", 283 ren 2 lei 4 (human being)
												"reng", //"reng", 284 reng 2 ran 2 (all the same)
												"ri", //"ri", 285 ri 4 chu 1 (sunrise)
												"rong", //"rong", 286 rong 2 yao 4 (glory)
												"rou", //"rou", 287 niu 2 rou 4 (beef)
												"ru", //"ru", 288 ru 2 guo 3 (if)
												"ruan", //"ruan", 289 rou 2 ruan 3 (soft)
												"rui", //"rui", 290 rui 4 zhi 4 (smart)
												"run", //"run", 291 shi 1 run 4 (wetness)
												"ruo", //"ruo", 292 ruo 4 xiao 3 (puniness)
												"sa", //"sa", 293 sa 1   (three)
												"sai", //"sai", 294 bi 3 sai 4 (compete)
												"san", //"san", 295 fen 1 san 4 (disperse)
												"sang", //"sang", 296 sang 4   (die)
												"sao", //"sao", 297 da 3 sao 3 (sweep)
												"se", //"se", 298 yan 2 se 4 (color)
												"sen", //"sen", 299 sen 1 lin 2 (forest)
												"seng", //"seng", 300 seng 1 lv 3 (monk)
												"sha", //"sha", 301 sha 1 chang 3 (battlefield)
												"shai", //"shai", 302 ri 4 shai 4 (be exposed to the sun)
												"shan", //"shan", 303 shan 4 liang 2 (goodness)
												"shang", //"shang", 304 shang 4 mian 4 (top)
												"shao", //"shao", 305 shao 4 nian 2 (youth)
												"she", //"she", 306 she 2   (snake)
												"shei", //"shei", 307 shei 2   (who)
												"shen", //"shen", 308 shen 2 me 5 (what)
												"sheng", //"sheng", 309 sheng 1 yin 1 (voice)
												"shi", //"shi", 310 shi 4 fei 1 (dispute)
												"shou", //"shou", 311 shou 3   (hand)
												"shu", //"shu", 312 shu 4 mu 4 (tree)
												"shua", //"shua", 313 shua 1 zi 5 (brush)
												"shuai", //"shuai", 314 shuai 1 da 3 (beat)
												"shuan", //"shuan", 315 men 2 shuan 1 (latch)
												"shuang", //"shuang", 316 shuang 1   (pair)
												"shui", //"shui", 317 shui 3   (water)
												"shun", //"shun", 318 shun 4 li 4 (all right)
												"shuo", //"shuo", 319 shuo 1   (say)
												"si", //"si", 320 si 4   (four)
												"song", //"song", 321 song 4 bie 2 (send-off)
												"sou", //"sou", 322 sou 1 cha 2 (search)
												"su", //"su", 323 su 4 du 4 (speed)
												"suan", //"suan", 324 suan 4 fa 3 (arithmetic)
												"sui", //"sui", 325 sui 1 ran 2 (though)
												"sun", //"sun", 326 sun 3 shi 1 (loss)
												"suo", //"suo", 327 suo 3 yi 3 (so)
												"ta", //"ta", 328 ta 1 men 2 (they)
												"tai", //"tai", 329 tai 4   (too)
												"tan", //"tan", 330 tan 2 hua 4 (talk)
												"tang", //"tang", 331 tang 2   (sugar)
												"tao", //"tao", 332 tao 2 pao 3 (flee)
												"te", //"te", 333 te 4 bie 2 (special)
												"tei", //"tei", 334 tei 1   (very)
												"teng", //"teng", 335 ben 1 teng 2 (riot)
												"ti", //"ti", 336 ti 1 zi 5 (ladder)
												"tian", //"tian", 337 tian 1   (sky)
												"tiao", //"tiao", 338 tiao 4 yue 4 (jump)
												"tie", //"tie", 339 tie 3   (iron)
												"ting", //"ting", 340 ting 1   (listen)
												"tong", //"tong", 341 tong 3 yi 1 (unify)
												"tou", //"tou", 342 tou 2   (head)
												"tu", //"tu", 343 tu 3 di 4 (earth)
												"tuan", //"tuan", 344 tuan 2 jie 2 (solidify)
												"tui", //"tui", 345 tui 1 dong 4 (push)
												"tun", //"tun", 346 tun 2 ji 1 (store up)
												"tuo", //"tuo", 347 tuo 1 yi 1 (undress)
												"wa", //"wa", 348 qing 1 wa 1 (frog)
												"wai", //"wai", 349 wai 4 mian 4 (outside)
												"wan", //"wan", 350 wan 4   (ten thousands)
												"wang", //"wang", 351 si 3 wang 2 (death)
												"wei", //"wei", 352 wei 3 da 4 (great)
												"wen", //"wen", 353 wen 2 hua 4 (culture)
												"weng", //"weng", 354 lao 3 weng 1 (oldman)
												"wo", //"wo", 355 wo 3   (I)
												"wu", //"wu", 356 wu 2 lun 4 (no matter what)
												"xi", //"xi", 357 xi 1 fang 1 (west)
												"xia", //"xia", 358 xia 4 mian 4 (bottom)
												"xian", //"xian", 359 xian 4 zai 4 (now)
												"xiang", //"xiang", 360 xiang 4   (like)
												"xiao", //"xiao", 361 xiao 3   (small)
												"xie", //"xie", 362 xie 3   (write)
												"xin", //"xin", 363 xin 1   (new)
												"xing", //"xing", 364 xing 2 dong 4 (act)
												"xiong", //"xiong", 365 xiong 2   (bear)
												"xiu", //"xiu", 366 xiu 1 xi 5 (break)
												"xu", //"xu", 367 xu 1 yao 4 (need)
												"xuan", //"xuan", 368 xuan 1 bu 4 (declare)
												"xue", //"xue", 369 xue 3   (snow)
												"xun", //"xun", 370 xun 2 wen 4 (ask for)
												"ya", //"ya", 371 ya 4 zhou 1 (Asia)
												"yan", //"yan", 372 yan 4 zi 5 (swallow)
												"yang", //"yang", 373 tai 4 yang 2 (sun)
												"yao", //"yao", 374 yao 1 qiu 2 (require)
												"ye", //"ye", 375 ye 2 ye 5 (grandfather)
												"yi", //"yi", 376 yi 1   (one)
												"yin", //"yin", 377 yin 1 yue 4 (music)
												"ying", //"ying", 378 ying 1 gai 1 (should)
												"yo", //"yo", 379 yo 5   (function word)
												"yong", //"yong", 380 yong 3 yuan 3 (forever)
												"you", //"you", 381 you 2 yu 2 (due to)
												"yu", //"yu", 382 yu 2   (fish)
												"yuan", //"yuan", 383 yuan 2 lai 2 (formerly)
												"yue", //"yue", 384 yue 4   (month)
												"yun", //"yun", 385 yun 2   (cloud)
												"za", //"za", 386 za 2 luan 4 (disorder)
												"zai", //"zai", 387 zai 4 jian 4 (farewell)
												"zan", //"zan", 388 zan 2 men 5 (our)
												"zang", //"zang", 389 ang 1 zang 1 (dirty)
												"zao", //"zao", 390 zao 3 chen 2 (morning)
												"ze", //"ze", 391 ze 2 ren 4 (response)
												"zei", //"zei", 392 zei 2   (thief)
												"zen", //"zen", 393 zan 4 yang 2 (praise)
												"zeng", //"zeng", 394 zeng 1 jia 1 (add)
												"zha", //"zha", 395 zha 4 dan 4 (bomb)
												"zhai", //"zhai", 396 qian 4 zhai 4 (owe)
												"zhan", //"zhan", 397 zhan 4 li 4 (stand)
												"zhang", //"zhang", 398 zhang 1 kai 1 (open)
												"zhao", //"zhao", 399 zhao 1 huan 4 (summon)
												"zhe", //"zhe", 400 zhe 4 li 3 (here)
												"zhei", //"zhei", 401 zhei 5   (this)
												"zhen", //"zhen", 402 zhen 1 zheng 4 (real)
												"zheng", //"zheng", 403 zheng 4 yi 4 (justice)
												"zhi", //"zhi", 404 yi 4 zhi 4 (restrain)
												"zhong", //"zhong", 405 zhong 1 guo 2 (China)
												"zhou", //"zhou", 406 si 4 zhou 1 (around)
												"zhu", //"zhu", 407 zhu 1   (pig)
												"zhua", //"zhua", 408 zhua 1   (grab)
												"zhuai", //"zhuai", 409 zhuai 4   (pull)
												"zhuan", //"zhuan", 410 zhuan 1   (brick)
												"zhuang", //"zhuang", 411 zhuang 1   (pretend)
												"zhui", //"zhui", 412 zhui 1   (chase)
												"zhun", //"zhun", 413 zhun 3   (precise)
												"zhuo", //"zhuo", 414 zhuo 1   (table)
												"zi", //"zi", 415 zi 4   (character)
												"zong", //"zong", 416 zong 3   (total)
												"zou", //"zou", 417 zou 3   (walk)
												"zu", //"zu", 418 zu 1   (rent)
												"zuan", //"zuan", 419 zuan 4   (diamond)
												"zui", //"zui", 420 zui 4   (most)
												"zun", //"zun", 421 zun 1   (respect)
												"zuo", //"zuo", 422 zuo 4   (sit)
												"ERROR" //THE VALUE EXCEEDS THE TOTAL NUMBER OF PHONEMES @ta
};

HXTTSEngineSAPI::HXTTSEngineSAPI(void)
: m_ppszTokenIds(NULL),
  m_numTokenIds(0)
{
	m_voiceIndex = -1;
	m_avSyncAdjust = 0.200;
}

HXTTSEngineSAPI::~HXTTSEngineSAPI(void)
{
	if (m_ppszTokenIds)
	{
		for (int i = 0; i < m_numTokenIds; i++)
			delete [] m_ppszTokenIds[i];
		delete [] m_ppszTokenIds;
		m_ppszTokenIds = NULL;
		m_numTokenIds = 0;
	}
}

/**
 * Populate the list of voices
 *
 * SAPI code adpated from http://www.generation5.org/content/2002/sr04.asp and MS CoffeeShop Demo
 *
 */
void HXTTSEngineSAPI::PopulateVoices()
{
	// Initialise COM
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

	//USES_CONVERSION;

	HRESULT hResult;
	
    //CComPtr<IEnumSpObjectTokens>    cpEnum;
	IEnumSpObjectTokens				*cpEnum;
    CSpDynamicString*				szDescription;
    ISpObjectToken                  *pToken = NULL;

    ULONG ulIndex = 0, ulNumTokens = 0/*, ulCurToken = -1*/;

	hResult = SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum);

	if (hResult == S_OK) {
		hResult = cpEnum->GetCount( &ulNumTokens );
		
		if (SUCCEEDED(hResult) && ulNumTokens != 0) 
		{
			szDescription = new CSpDynamicString [ulNumTokens];
			if (m_ppszTokenIds)
			{
				for (int i = 0; i < m_numTokenIds; i++)
					delete [] m_ppszTokenIds[i];
				delete [] m_ppszTokenIds;
				m_ppszTokenIds = NULL;
				m_numTokenIds = 0;
			}
            m_ppszTokenIds = new WCHAR* [ulNumTokens];
			m_numTokenIds = ulNumTokens;

            ZeroMemory(m_ppszTokenIds, ulNumTokens * sizeof(WCHAR *));

			m_voices.clear();

			while (cpEnum->Next(1, &pToken, NULL) == S_OK) 
			{
				hResult = SpGetDescription(pToken, &szDescription[ulIndex]);
				_ASSERTE(SUCCEEDED(hResult));

				// add to list of voices
				size_t converted = 0;
				size_t slength = wcslen(szDescription[ulIndex]);
				char* buffer = new char[slength+1];
				wcstombs_s(&converted, buffer, slength+1, szDescription[ulIndex], _TRUNCATE);
				m_voices.push_back(string(buffer));
				delete [] buffer;

                hResult = pToken->GetId(&m_ppszTokenIds[ulIndex]);
				_ASSERTE(SUCCEEDED(hResult));

				ulIndex++;				
				pToken->Release();
				pToken = NULL;
			}
			delete [] szDescription;
		}
		
	}

	// Unload COM
	CoUninitialize();
}

/**
 * Set the voice
 */
void HXTTSEngineSAPI::SetVoice(string& voice)
{

	// check to see if we need to populate the voices list
	if (m_voices.empty())
	{
		PopulateVoices();
	}

	
	// find the voice in the m_voices
	vector<HXViseme>::iterator voiceIter;
	m_voiceIndex = -1;
	for(size_t vi = 0; vi < m_voices.size(); vi++)
	{
		if (m_voices.at(vi) == voice)
		{
			m_voiceIndex = vi;
			break;
		}
	}
}
	




/**
 * Get list of available voices
 */
void HXTTSEngineSAPI::GetVoices(vector<string>& voices)
{
	// check to see if we need to populate the voices list
	if (m_voices.empty())
	{
		PopulateVoices();	
	}

	voices = m_voices;

}

void HXTTSEngineSAPI::SetEffect(string& /*effect*/, string& /*value*/)
{
}

/**
 * generate the speech to be played
 *
 * Input
 *   - text, the text to speak
 * Output
 *   - TODO: audio, the audio to be played (either a filename or in memory audio)
 *   - frames, the sequence of viseme frames to be played
 */
HRESULT HXTTSEngineSAPI::GenerateSpeech(const wstring& text, string& audio, vector<vector<HXViseme>>& frames)
{
	HRESULT hr;

    CComPtr<ISpVoice>   cpVoice;

	hr = cpVoice.CoCreateInstance( CLSID_SpVoice );
	if ( FAILED( hr ) )
	{
		WNotify(NULL, L"Error creating voice interface.");
		return hr;
	}

	hr = cpVoice->SetNotifyWin32Event();

	if (g_config.voiceLanguage == Chinese)
	{
		// CHINESE LOOKING AT PHONEMES @ta
		hr = cpVoice->SetInterest(SPFEI(SPEI_PHONEME)|SPFEI(SPEI_END_INPUT_STREAM)|SPFEI(SPEI_WORD_BOUNDARY)|SPFEI(SPEI_SENTENCE_BOUNDARY)|SPFEI(SPEI_TTS_BOOKMARK),
								  SPFEI(SPEI_PHONEME)|SPFEI(SPEI_END_INPUT_STREAM)|SPFEI(SPEI_WORD_BOUNDARY)|SPFEI(SPEI_SENTENCE_BOUNDARY)|SPFEI(SPEI_TTS_BOOKMARK));
	}
	else
	{
		hr = cpVoice->SetInterest(SPFEI(SPEI_VISEME)|SPFEI(SPEI_END_INPUT_STREAM)|SPFEI(SPEI_WORD_BOUNDARY)|SPFEI(SPEI_SENTENCE_BOUNDARY)|SPFEI(SPEI_TTS_BOOKMARK),
							      SPFEI(SPEI_VISEME)|SPFEI(SPEI_END_INPUT_STREAM)|SPFEI(SPEI_WORD_BOUNDARY)|SPFEI(SPEI_SENTENCE_BOUNDARY)|SPFEI(SPEI_TTS_BOOKMARK));
	}

	if ( FAILED( hr ) )
	{
		#ifdef _DEBUG
			WNotify(NULL, L"Warning: voice does not support all the required features.");
		#endif
	}

	// code adapted from 
	//  http://groups.google.com/group/microsoft.public.speech_tech.sdk/browse_thread/thread/47abdb6ac6281cd4/5a962ca5684e4ad4
	//
	CComPtr <ISpStream> cpStream; // Pass-through object between the voice and	file stream object
	CComPtr <ISpStream> cpFileStream; // Actually generates wave file
    //CComPtr<ISpeechMemoryStream> cpBuff;

	/*	
	IStream   *pStream; 
	CreateStreamOnHGlobal(NULL, TRUE, &pStream); 
	*/
	//CSpStreamFormat format(SPSF_44kHz16BitStereo, &hr); //set the format for the wav
	// SPSF_22kHz16BitMono is the preferred wav format of the Microsoft English TTS engine
	// but 16kHz sounds better, SPSF_16kHz16BitMono

	CSpStreamFormat format; //set the format for the wav
	switch (m_enginekHz )
	{
	case 44:
		format.AssignFormat(SPSF_44kHz16BitMono);
		break;
	case 16:
		format.AssignFormat(SPSF_16kHz16BitMono);
		break;
	case 22:
	default:
		format.AssignFormat(SPSF_22kHz16BitMono);
	}

	// Generate file name in the system temporary directory
	if (IsOSVistaOrLater())
		audio = WStringToString(GetTemporaryFile(L"HXAUDIO"));
	else
		audio = "headxtmp.wav";

	// Create wav file stream	
	hr = SPBindToFile(StringToWString(audio).c_str(),  SPFM_CREATE_ALWAYS,  &cpFileStream, &format.FormatId(),format.WaveFormatExPtr() );
	if( FAILED( hr ) )
    {
        MessageBox( NULL, _T("Unable to bind to file"), _T("Error"), MB_OK );
		//return hr;
	}

	// Create pass-through stream and set its base stream to be the file stream
	hr = cpStream.CoCreateInstance(CLSID_SpStream);
	if ( FAILED( hr ) )
	{
		WNotify(NULL, L"Error creating voice stream.");
		//CoUninitialize();
		return hr;
	}

	//m_spStream->SetBaseStream(pStream, Fmt.FormatId(), Fmt.WaveFormatExPtr());
	hr = cpStream->SetBaseStream(cpFileStream, format.FormatId(),format.WaveFormatExPtr());
	//hr = cpStream->SetBaseStream(pStream, format.FormatId(),format.WaveFormatExPtr()); // attempting to get wave data!
	if ( FAILED( hr ) )
	{
		WNotify(NULL, L"Error creating file stream.");
		//CoUninitialize();
		return hr;
	}
	
	
	/*
	WAVEFORMATEX  *pFormat;
	GUID type = SPDFID_WaveFormatEx;
	cpFileStream->GetFormat(&type,&pFormat);
    */
	//format.WaveFormatExPtr()->nAvgBytesPerSec;

	// Connect the voice to the pass-through stream
	hr = cpVoice->SetOutput(cpStream, FALSE);

	// set speech rate
	hr = cpVoice->SetRate((long)m_rate);

	// set voice
	if (m_voiceIndex != -1)
	{
		CComPtr<ISpObjectToken>   pToken;
		SpGetTokenFromId(m_ppszTokenIds[m_voiceIndex], &pToken, FALSE);
		hr = cpVoice->SetVoice(pToken);
		if( FAILED( hr ) )
		{
			MessageBox( NULL, _T("Error setting voice speech"), _T("Error"), MB_OK );
			return hr;
		}
	}

	/*
	// Collect the data stream and Clone it so we have control of our own seek
	IStream   *pStreamClone; 
	//m_spStream->GetBaseStream(&pStream);
	pStream->Clone(&pStreamClone); 
	audio.clear();
	*/

	//hr = cpVoice->Speak( NULL, SPF_PURGEBEFORESPEAK, 0);
	// SPF_ASYNC | ((IsDlgButtonChecked( m_hWnd, IDC_SPEAKXML )) ? SPF_IS_XML : SPF_IS_NOT_XML
	//hr = cpVoice->Speak((LPCWSTR)text.c_str(), SPF_ASYNC, NULL); // Speak asynchronously
	//hr = cpVoice->Speak(L"This sounds normal ", 0, NULL );
	hr = cpVoice->Speak((LPCWSTR)text.c_str(), SPF_ASYNC | SPF_IS_XML, NULL); // Speak asynchronously
	if( FAILED( hr ) )
	{
		MessageBox( NULL, _T("Unable to speak"), _T("Error"), MB_OK );
		return hr;
	}
	
	ULONG ul;
	SPEVENT event;
	bool fDone = false; // Get set to true when speaking has finished
    
	double endpoint = 0.0;
	double startpoint = 0.0;
	double real_duration = 0.0;
	int previous_visemeCode = -1;

	/*
	// for reading audio data
	STATSTG   stats; 
	LARGE_INTEGER  liBeggining = { 0 }; 
	ULARGE_INTEGER  uli;
	ULONG   data_available = 0,  datasent = 0, bytesRead = 0; 
    */
	//ofstream out("viseme.txt"); // Open for writing

	unsigned int wordIndex = 0;

	while (!fDone)
	{
		hr = cpVoice->WaitForNotifyEvent(INFINITE); // Wait for some events
		//hr = cpVoice->WaitForNotifyEvent(10); // Wait for some events
		while (cpVoice->GetEvents(1, &event, &ul) == S_OK)
		{
			switch( event.eEventId )
			{
			case SPEI_VISEME:
				{
					// The high word is the duration, in milliseconds, of the current viseme. The low word is the code for the next viseme.
					double duration = HIWORD(event.wParam) / 1000.0;				
					//int next_visemeCode = LOWORD(event.wParam); // seems to always be zero!!

					// The low word current viseme code, the high word is the feature of the viseme
					int visemeCode = LOWORD(event.lParam);			

					// 
					if (previous_visemeCode != visemeCode)
					{	

						// add the previous to the sequence

						// adjust startpoint for av sync issues				
						if (startpoint+real_duration > m_avSyncAdjust)
						{
							startpoint -= m_avSyncAdjust;
						}

						endpoint = startpoint + real_duration;

						//out << startpoint << ", " << real_duration << ", " << previous_visemeCode <<  ", " << endpoint << "\n";

						if (previous_visemeCode && previous_visemeCode < 22)
						{
							string viseme = aMapVisemeToImage[previous_visemeCode];

							ToHXViseme(viseme, endpoint, ((startpoint > 0) ? startpoint : 0), frames);
						}
					



						// get the new visemes start point
						startpoint = event.ullAudioStreamOffset / (format.WaveFormatExPtr()->nAvgBytesPerSec + 0.0);

						// get its duration
						real_duration = duration;
					}
					
					else
					{
						// if the same as previous then add to the duration
						real_duration += duration; 
					}


					previous_visemeCode = visemeCode;
					break;



				}

				case SPEI_PHONEME: // We know it's Chinese
				{
					
					double duration = HIWORD(event.wParam) / 1000.0;				
					int phonemeCode = LOWORD(event.lParam);			

					// NEED TO FIX THIS CODE HERE TO MAP TO VISEMES AT APPROPRIATE TIMES @ta
					if (previous_visemeCode != phonemeCode)
					{			
						if (startpoint+real_duration > m_avSyncAdjust)
						{
							startpoint -= m_avSyncAdjust;
						}
						endpoint = startpoint + real_duration;
						//out << startpoint << ", " << real_duration << ", " << previous_visemeCode <<  ", " << endpoint << "\n";

						if (previous_visemeCode && previous_visemeCode < 423)
						{
							string phoneme = aMapChinesePhonemeToImage[previous_visemeCode];

							ToHXViseme(phoneme, endpoint, ((startpoint > 0) ? startpoint : 0), frames);
						}					
					// END NEED TO FIX THIS CODE HERE TO MAP TO VISEMES AT APPROPRIATE TIMES @ta

						startpoint = event.ullAudioStreamOffset / (format.WaveFormatExPtr()->nAvgBytesPerSec + 0.0);
						real_duration = duration;
					}
					
					else
					{
						real_duration += duration; 
					}


					previous_visemeCode = phonemeCode;
					break;

				}
			case SPEI_TTS_BOOKMARK:
			case SPEI_WORD_BOUNDARY:
				{
					SPVOICESTATUS   Stat;
					hr = cpVoice->GetStatus( &Stat, NULL );
					if( FAILED( hr ) )
					{
						//TTSAppStatusMessage( m_hWnd, _T("Voice GetStatus error\r\n") );
						return hr;
					}

					// Highlight word					
					//WPARAM nStart = (LPARAM)( Stat.ulInputWordPos / sizeof(char) );
					WPARAM nStart = (LPARAM)( Stat.ulInputWordPos );				
					LPARAM nLength = Stat.ulInputWordLen;
					//LPARAM nEnd = nStart + nLength;
					//TCHAR tempString[80];
					//StringCchCopyN( tempString, 80, (LPCWSTR)text.c_str() + nStart , nLength);
                    //tempString[ nEnd ] = '\0';

					// get the timing of the start of the word 
					double tStart = event.ullAudioStreamOffset / (format.WaveFormatExPtr()->nAvgBytesPerSec + 0.0);
					int fStart = (int)(tStart * m_fps);
					int fEnd = fStart+int(m_fps*0.1);
					if ((int)frames.size() < fEnd+1)
					{
						// resize to fit in data
						frames.resize(fEnd+1);
					}
					
					for (int fi = fStart; fi < fEnd; fi++)
					{
						wchar_t wordTag[100];
						swprintf_s(wordTag, 100, L"%c%d%c", 1, wordIndex, 1);
						wstring s = text;
						if (s.length() < nStart+nLength)
						{
							s = wstring(wordTag);
						}
						else
						{
							s = wstring(wordTag).append(text.substr(nStart,nLength));
						}
						frames[fi].push_back(HXViseme(s,tStart,0,0));
					}

					wordIndex++;

					//SendDlgItemMessage( m_hWnd, IDE_EDITBOX, EM_SETSEL, nStart, nEnd );
					
					//TTSAppStatusMessage( m_hWnd, _T("Wordboundary event\r\n") );
						
					break;
				}
			case SPEI_SENTENCE_BOUNDARY:
				{
					//real_duration = 0;
					//previous_visemeCode = 0;
					break;
				}
			case SPEI_END_INPUT_STREAM:
				{
					//g_window.ShowStatus(L"finished speaking!");
					fDone = true; // Stream ended
					break;
				}
			}
		}
	 
	}

	//out.close();
	
	cpVoice->WaitUntilDone( INFINITE );
	
	cpStream.Release();
	
	cpFileStream.Release();

	// now speak to default audio
	hr = cpVoice->SetOutput(NULL, FALSE);

	return hr;
}

// for testing only
void HXTTSEngineSAPI::GenerateSpeechOnly(const wstring& text)
{
	HRESULT hr;

	// Initialise COM
	CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
    CComPtr<ISpVoice>   cpVoice;

	hr = cpVoice.CoCreateInstance( CLSID_SpVoice );
	
	hr = cpVoice->Speak((LPCWSTR)text.c_str(), SPF_ASYNC | SPF_IS_NOT_XML, NULL); // Speak asynchronously
	if( FAILED( hr ) )
	{
		MessageBox( NULL, _T("Unable to speak"), _T("Error"), MB_OK );
	}

	cpVoice->WaitUntilDone( INFINITE );
	
	CoUninitialize();
}